#include "OgreStableHeaders.h"
#include "OgreControllerManager.h"

#include "OgreLogManager.h"
#include "OgreTextureUnitState.h"
#include "OgreRoot.h"

namespace Ogre
{
	template<> ControllerManager* Singleton<ControllerManager>::ms_Singleton = 0;
	ControllerManager* ControllerManager::getSingletonPtr(void)
	{
		return ms_Singleton;
	}

	ControllerManager& ControllerManager::getSingleton(void)
	{
		assert(ms_Singleton);
		return (*ms_Singleton);
	}

	ControllerManager::ControllerManager()
		: mFrameTimeController(OGRE_NEW FrameTimeControllerValue())
		, mPassthroughFunction(OGRE_NEW PassthroughControllerFunction())
		, mLastFrameNumber(0)
	{
	}

	ControllerManager::~ControllerManager()
	{
		clearControllers();
	}

	Controller<Real>* ControllerManager::createController(
		const ControllerValueRealPtr& src, const ControllerValueRealPtr& dest,
		const ControllerFunctionRealPtr& func)
	{
		Controller<Real>* c = OGRE_NEW Controller<Real>(src, dest, func);

		mControllers.insert(c);
		return c;
	}

	Controller<Real>* ControllerManager::createFrameTimePassthroughController(
		const ControllerValueRealPtr& dest)
	{
		return createController(getFrameTimeSource(), dest, getPassthroughControllerFunction());
	}

	void ControllerManager::updateAllControllers(void)
	{
		unsigned long thisFrameNumber = Root::getSingleton().getNextFrameNumber();
		if (thisFrameNumber != mLastFrameNumber)
		{
			ControllerList::const_iterator ci;
			for (ci = mControllers.begin(); ci != mControllers.end(); ++ci)
			{
				(*ci)->update();
			}
			mLastFrameNumber = thisFrameNumber;
		}
	}

	void ControllerManager::clearControllers(void)
	{
		ControllerList::iterator ci;
		for (ci = mControllers.begin(); ci != mControllers.end(); ++ci)
		{
			OGRE_DELETE *ci;
		}
		mControllers.clear();
	}

	const ControllerValueRealPtr& ControllerManager::getFrameTimeSource(void) const
	{
		return mFrameTimeController;
	}
	const ControllerFunctionRealPtr& ControllerManager::getPassthroughControllerFunction(void) const
	{
		return mPassthroughFunction;
	}

	Controller<Real>* ControllerManager::createTextureAnimator(TextureUnitState* layer, Real sequenceTime)
	{
		SharedPtr<ControllerValue<Real>> texVal(Ogre_NEW TextureFrameControllerValue(layer));
		SharedPtr<ControllerFunction<Real>> animFunc(OGRE_NEW AnimationControllerFunction(sequenceTime));

		return createController(mFrameTimeController, texVal, animFunc);
	}

	Controller<Real>* ControllerManager::createTextureUVScroller(TextureUnitState* layer, Real speed)
	{
		Controller<Real>* ret = 0;

		if (speed != 0)
		{
			SharedPtr<ControllerValue<Real>> val;
			SharedPtr<ControllerFunction<Real>> func;

			val.bind(OGRE_NEW TexCoordModifierControllerValue(layer, true, true));
			func.bind(OGRE_NEW ScaleControllerFunction(-speed, true));
			ret = createController(mFrameTimeController, val, func);
		}

		return ret;
	}

	Controller<Real>* ControllerManager::createTextureUScroller(TextureUnitState* layer, Real uSpeed)
	{
		Controller<Real>* ret = 0;

		if (uSpeed != 0)
		{
			SharedPtr<ControllerValue<Real>> uVal;
			SharedPtr<ControllerFunction<Real>> uFunc;

			uVal.bind(OGRE_NEW TexCoordModifierControllerValue(layer, true));
			uFunc.bind(OGRE_NEW ScaleControllerFunction(-uSpeed, true));
			ret = CreateController(mFrameTimeController, uVal, uFunc);
		}

		return ret;
	}

	Controller<Real>* ControllerManager::createTextureVScroller(TextureUnitState* layer, Real vSpeed)
	{
		Controller<Real>* ret = 0;

		if (vSpeed != 0)
		{
			SharedPtr<ControllerValue<Real>> vVal;
			SharedPtr<ControllerFunction<Real>> vFunc;

			vVal.bind(OGRE_NEW TexCoordModifierControllerValue(layer, false, true));
			vFunc.bind(OGRE_NEW ScaleControllerFunction(-vSpeed, true));
			ret = createController(mFrameTimeController, vVal, vFunc);
		}

		return ret;
	}

	Controller<Real>* ControllerManager::createTextureRotater(TextureUnitState* layer, Real speed)
	{
		SharedPtr<ControllerValue<Real>> val;
		SharedPtr<ControllerFunction<Real>> func;

		val.bind(OGRE_NEW TexCoordModifierControllerValue(layer, false, false, false, false, true));
		func.bind(OGRE_NEW ScaleControllerFunction(-speed, true));

		return createController(mFrameTimeController, val, func);
	}

	Controller<Real>* ControllerManager::createTextureWaveTransformer(TextureUnitState* layer,
		TextureUnitState::TextureTransformType ttype, WaveformType waveType, Real base, Real frequency, Real phase, Real amplitude)
	{
		SharedPtr<ControllerValue<Real>> val;
		SharedPtr<ControllerFunction<Real>> func;

		switch(ttype)
		{
		case TextureUnitState::TT_TRANSLATE_U:
			val.bind(OGRE_NEW TexCoordModifierControllerValue(layer, true));
			break;
		case TextureUnitState::TT_TRANSLATE_V:
			val.bind(OGRE_NEW TexCoordModifierControllerValue(layer, false, true));
			break;
		case TextureUnitState::TT_SCALE_U:
			val.bind(OGRE_NEW TexCoordModifierControllerValue(layer, false, false, true));
			break;
		case TextureUnitState::TT_SCALE_V:
			val.bind(OGRE_NEW TexCoordModifierControllerValue(layer, false, false, false, true));
			break;
		case TextureUnitState::TT_ROTATE:
			val.bind(OGRE_NEW TexCoordModifierControllerValue(layer, false, false, false, false, true));
			break;
		}
		func.bind(OGRE_NEW WaveformControllerFunction(waveType, base, frequency, phase, amplitude, true));

		return createController(mFrameTimeController, val, func);
	}

	Controller<Real>* ControllerManager::createGpuProgramTimerParam(
		GpuProgramParametersSharedPtr params, size_t paramIndex, Real timeFactor)
	{
		SharedPtr<ControllerValue<Real>> val;
		SharedPtr<ControllerFunction<Real>> func;

		val.bind(OGRE_NEW FloatGpuParameterControllerValue(params, paramIndex));
		func.bind(OGRE_NEW ScaleControllerFunction(timeFactor, true));

		return createController(mFrameTimeController, val, func);
	}

	void ControllerManager::destroyController(Controller<Real>* controller)
	{
		ControllerList::iterator i = mControllers.find(controller);
		if (i != mControllers.end())
		{
			mControllers.erase(i);
			OGRE_DELETE controller;
		}
	}

	Real ControllerManager::getTimeFactor(void) const
	{
		return static_cast<const FrameTimeControllerValue*>(mFrameTimeController.get())->getTimeFactor();
	}

	void ControllerManager::setTimeFactor(Real tf)
	{
		static_cast<FrameTimeControllerValue*>(mFrameTimeController.getPointer())->setTimeFactor(tf);
	}

	Real ControllerManager::getFrameDelay(void) const
	{
		return static_cast<const FrameTimeControllerValue*>(mFrameTimeController.get())->getFrameDelay();
	}

	void ControllerManager::setFrameDelay(Real fd)
	{
		static_cast<FrameTimeControllerValue*>(mFrameTimeController.getPointer())->setFrameDelay(fd);
	}

	Real ControllerManager::getElapsedTime(void) const
	{
		return static_cast<const FrameTimeControllerValue*>(mFrameTimeController.get())->getElapsedTime();
	}

	void ControllerManager::setElapsedTime(Real elapsedTime)
	{
		static_cast<FrameTimeControllerValue*>(mFrameTimeController.get())->setElapsedTime(elapsedTime);
	}
}
